#include <string.h>
#include <stdlib.h>
#include <assert.h>

#include "symbol.h"
#include "error.h"
#include "parser.h"
#include "gp_list.h"
#include "common.h"
#include "sym_table.h"


static int var_id_g = 0; // 变量的编号，方便调试
bool is_literal_string(var_t *var);

void gen_name(char *out)
{
	if(!out){
		SYSTEM_FATAL_ERR(POINTER_IS_NULL);		
	}
		
	int static name_id = 1;
	char tmp[GEN_NAME_MAX_LEN] = {0};
	sprintf(tmp, "%s%d", "L", name_id++); // 产生一个新的名字
	strcpy(out, tmp);		
}

var_t *new_var(bool is_ext, symbol_e type, bool is_ptr,
		                 const char *name,  var_t *init, int line)
{
	if(name[0] == 0)
		return NULL;

	int err_flag = 0;
	if(type == INVALID) { // 语法分析的时候已经报错
		type = INT;  // 已经出错，标记为 int
		err_flag = 1;
	}	 

	if(type == VOID) { // 不允许使用 void 类型变量
		if(is_ptr) {
			sem_err(VOID_POINTER_NOT_SUPPORTED, ERROR, name, NULL);
		} else {
			sem_err(VAR_DECLARED_VOID, ERROR, name, NULL); 
		}
		err_flag = 1;
		type = INT; // 已经出错，标记为 int
	}

	var_t *var = calloc(1, sizeof(var_t));
	if(!var){
		SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
		return NULL;
	}
	// 设置作用域
	get_cur_scope(&var->scope_path, SYMBOL_TYPE_VAR); 
	INIT_HLIST_NODE(&var->hnode);
    var->is_ext = is_ext;
    var->is_ptr = is_ptr;
	var->err_flag = err_flag;
    var->type = type;
    var->is_left = true;
	var->init_val = init;
	var->index = var_id_g++;
	var->line_num = line;
	strcpy(var->name, name);       
	if(is_ext){			
		var->size = 0;		
	} else {
		if(is_ptr){			
			var->size = 4;
		} else {
			var->size = (type == INT) ? 4 : 1;
		}
	}
	return var;
}


var_t *new_arr(bool is_ext, symbol_e type, bool is_ptr,
		const char *name, int len, int line)
{
	int err_flag = 0;
	if(name[0] == 0)
		return NULL;
	
	if(len == ARR_SIZE_INVALID) { // 语法分析的时候已经报错
		len = 0; // 已经出错，标记为 0
		err_flag = 1;
	}
		
	if(type == INVALID) { // 语法分析的时候已经报错
		type = INT;  // 已经出错，标记为 int
		err_flag = 1;
	}	 
   
	if(type == VOID) { // 不允许使用 void 类型变量
		if(is_ptr) {
			sem_err(VOID_POINTER_NOT_SUPPORTED, ERROR, name, NULL);
		} else {
			sem_err(VAR_DECLARED_VOID, ERROR, name, NULL); 
		}	
		err_flag = 1;
		type = INT; // 已经出错，标记为 int
	}

	// if(is_ptr){
	// 	sem_err(ARRAY_ELEMENT_TYPE_INVALID, ERROR, name, NULL);
	// 	is_ptr = false;  // 后面可能会支持指针
	// 	err_flag = 1;
	// }

	var_t *var = calloc(1, sizeof(var_t));
	if(!var){
		SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
		return NULL;
	}

	get_cur_scope(&var->scope_path, SYMBOL_TYPE_VAR); // 设置作用域
	INIT_HLIST_NODE(&var->hnode);
    INIT_LIST_HEAD(&var->arr_init_val);

    var->is_ext = is_ext;
	var->is_ptr = is_ptr;
    var->type = type;
	var->is_left = true;
	var->is_arr = true;
	var->ele_num = len;
	var->err_flag = err_flag;
	var->index = var_id_g++;
	var->line_num = line; // 报错的时候可能用
	strcpy(var->name, name);
	if(is_ext){			
		var->size = 0;		
	} else {
		if(is_ptr)
			var->size = 4 * len;	
		else 
			var->size = (type == INT) ? 4 * len : len;	
	}
	return var;
}

void var_destroy(var_t *var)
{
	if(!var)
		return;

	free(var->scope_path.path);
	
	if(is_literal_string(var))
		free(var->string_val);
	
    if(var->is_arr) {
        gp_list_free(&var->arr_init_val);
    }

	free(var);
}

void fun_params_destroy(struct list_head *head)
{
	if(!head)
		return;
	if(list_empty(head))
		return;
	gp_node_t *cur, *next;

	list_for_each_entry_safe(cur, next, head, entry){
		list_del(&cur->entry);
		var_t *var = cur->addr;
		hlist_del(&var->hnode); // 从变量表中删除
		sym_tab_g.var_num--;
		gp_list_del_node(var, &sym_tab_g.var_tab_head); 
		var_destroy(var);
		free(cur);
	}

}

void fun_destroy(fun_t *fun)
{
	if(!fun)
		return;
	fun_params_destroy(fun->para_list_head);
	free(fun->para_list_head);
	free(fun->scope_path.path);
	free(fun);
}

var_t *new_literal(const void *val, symbol_e token)
{
	var_t *var = calloc(1, sizeof(var_t));	
	if(!var) {
		SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
		return NULL;
	}

    INIT_HLIST_NODE(&var->hnode); 
	INIT_LIST_HEAD(&var->arr_init_val);
    var->is_literal = true;
	var->is_left = false;
    var->index = var_id_g++;

    if(token == NUM) {
        strcpy(var->name, "<int>"); // 特殊变量名
        var->type = INT;
        var->int_val = *(int *)val;
        var->size = 4;	
    } else if(token == CHARA) {
        strcpy(var->name, "<char>"); // 特殊变量名
        var->type = CHAR;
        var->char_val = *(char *)val;
        var->size = 1;
    } else if(token == STRING) { 
        gen_name(var->name);
        var->type = CHAR;
        char *str_mem = malloc(strlen(val) + 1);
        if(!str_mem) {
            free(var);
            SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
		    return NULL;
        }
        strcpy(str_mem, val);
        var->is_arr = true;
        var->string_val = str_mem;
        var->size = strlen(val) + 1;
        var->ele_num = strlen(val) + 1;
    }

	return var;
}

bool is_literal_string(var_t *var)
{
    if(!var)
        return false;
    return (var->is_literal) && (var->is_arr);
}



fun_t *new_fun(symbol_e type, bool ptr, const char *name, 
		struct list_head *para_list_head, int line)
{
	if(name[0] == 0) {
		gp_list_free(para_list_head); // 参数还在变量表中，方便后面的解析
		free(para_list_head);
		return NULL; 
	}
		
	int err_flag = 0;
	if(ptr && (type == VOID)) {
		// 不支持返回 void 指针的函数
		sem_err(RETURN_TYPE_IS_VOID_POINTER, ERROR, name, NULL);
		err_flag = 1;
	}

	if(para_list_head && list_empty(para_list_head)) {
		// 缺少有效参数
		err_flag = 1;
	}

	fun_t *fun = calloc(1, sizeof(fun_t));
	if(!fun){
		SYSTEM_FATAL_ERR(MEM_ALLOC_FAILED);
	}

	get_cur_scope(&fun->scope_path, SYMBOL_TYPE_FUN);
    fun->is_ptr = ptr;
    fun->type = type;
	strcpy(fun->name, name);
	fun->para_list_head = para_list_head;
    if(!para_list_head)
        fun->para_len = 0;
    else 
        fun->para_len = get_list_len(fun->para_list_head);
    	
	fun->line_num = line;
	return fun;
}





